#pragma once

#include <vector>
#include <map>
#include "Includes.h"

using namespace std;
//Resource manager with crc checking
template 
< class CResource >
class CResourceCRCMgr
{
protected:
	typedef pair< string, CResource* > StrLink;
	typedef pair< mUInt , CResource* > CRCLink;

	vector< StrLink > m_NameMap;
	vector< CRCLink > m_CRCMap;

	CResource *SearchResource( string a_sName )
	{
		for each ( StrLink Link in m_NameMap)
			if (a_sName == Link.first)
				return Link.second;
		return NULL;
	}

	CResource *SearchResource( mUInt a_uCRC )
	{
		for each ( CRCLink Link in m_CRCMap)
			if (a_uCRC == Link.first)
				return Link.second;
		return NULL;
	}

	virtual CResource *CreateResource( std::string &a_sName )
	{
		return new CResource(a_sName);
	}

	virtual mVoid DestroyResource( CResource *a_pResource )
	{
		delete a_pResource;
	}

public:
    CResourceCRCMgr             ( )
    {
    }

    CResource *Allocate ( std::string &a_sName )
    {
        CResource *pResource = SearchResource(a_sName);
		if (pResource != NULL)
			return pResource;

		CResource *pNewRes = CreateResource(a_sName);
        if (pNewRes == NULL)
            return NULL;

		mUInt uCRC = pNewRes->GetCRC();
		
		pResource = SearchResource(uCRC);
		if (pResource != NULL)
		{
			DestroyResource(pNewRes);
			m_NameMap.push_back(StrLink(a_sName, pResource));
			return pResource;
		}
        
		m_NameMap.push_back(StrLink(a_sName, pNewRes));
		m_CRCMap.push_back(CRCLink(uCRC, pNewRes));
        
        return pNewRes;
    }

    mVoid DeAllocate( CResource *a_pResource )
    {
        if ( a_pResource == NULL )
            return;

        vector< StrLink > :: iterator StrIterator;
        vector< CRCLink > :: iterator CRCIterator;

        for (StrIterator = m_NameMap.begin(); StrIterator != m_NameMap.end();)
        {
            if (StrIterator->second == a_pResource)
                m_NameMap.erase(StrIterator);
            else
                ++StrIterator;
        }

        for (CRCIterator = m_CRCMap.begin(); CRCIterator != m_CRCMap.end();)
        {
            if (CRCIterator->second == a_pResource)
                m_CRCMap.erase(CRCIterator);
            else
                ++CRCIterator;
        }

        DestroyResource(a_pResource);
    }

    ~CResourceCRCMgr ( )
    {
		m_NameMap.clear();
		for each (CRCLink Link in m_CRCMap)
			delete Link.second;
		m_CRCMap.clear();
    }

};

//Resource manager without crc checking - and it is fucking faster!
template 
< class CResource >
class CResourceMgr
{
protected:
    std::map< string, CResource* > m_NameMap;

    CResource *SearchResource( string &a_sName )
    {
        /*for each ( StrLink Link in m_NameMap)
            if (a_sName == Link.first)
                return Link.second;
        return NULL;*/
        std::map< string, CResource* >::iterator itResult;
        itResult = m_NameMap.find(a_sName);
        if (itResult == m_NameMap.end())
            return NULL;
        return itResult->second;
    }

    virtual CResource *CreateResource( std::string &a_sName )
    {
        return new CResource(a_sName);
    }

    virtual mVoid DestroyResource( CResource *a_pResource )
    {
        delete a_pResource;
    }

public:
    CResourceMgr             ( )
    {
    }

    CResource *Allocate ( std::string a_sName )
    {
        CResource *pResource = SearchResource(a_sName);
        if (pResource != NULL)
            return pResource;

        CResource *pNewRes = CreateResource(a_sName);
        if (pNewRes == NULL)
            return NULL;

        //m_NameMap.push_back(a_sName, pNewRes);
        m_NameMap[a_sName] = pNewRes;

        return pNewRes;
    }

    mVoid DeAllocate( CResource *a_pResource )
    {
        if ( a_pResource == NULL )
            return;

        vector< StrLink > :: iterator StrIterator;

        for (StrIterator = m_NameMap.begin(); StrIterator != m_NameMap.end();)
        {
            if (StrIterator->second == a_pResource)
                m_NameMap.erase(StrIterator);
            else
                ++StrIterator;
        }

        DestroyResource(a_pResource);
    }

    ~CResourceMgr ( )
    {
        m_CRCMap.clear();
        for each (StrLink Link in m_NameMap)
            delete Link.second;
        m_NameMap.clear();
    }

};
//template 
//< class Shader >
//class ShaderMgr: public CResourceMgr< Shader >
//{
//protected:
//
//	Shader *CreateResource( std::string a_sName )
//	{
//		Shader *pShader = new Shader(a_sName);
//		pShader->Compile();
//		return pShader;
//	}
//
//public:
//	ShaderMgr( ):
//	  CResourceMgr( ) {}
//
//    ~ShaderMgr ( )
//    {
//        (*g_pDebug) << "Deleting shaders...\n";
//    }
//};
//
//template 
//< class Texture2D >
//class TextureMgr: public CResourceMgr< Texture2D >
//{
//protected:
//    Texture2D *CreateResource( std::string a_sName )
//    {
//        Texture2D *pTexture = Texture2D::CreateTexture2D();
//        if (!pTexture->CreateFromFile(a_sName))
//        {
//            delete pTexture;
//            return NULL;
//        }
//
//        return pTexture;
//    }
//
//public:
//    TextureMgr ( ):
//      CResourceMgr( ) {}
//
//    ~TextureMgr( )
//    {
//        (*g_pDebug) << "Deleting textures...\n";
//    }
//};